From ddce88a1586871bc8340940887943fb86f5fb81e Mon Sep 17 00:00:00 2001 From: Ralf Horstmann Date: Sat, 16 Jan 2016 14:50:09 +0100 Subject: [PATCH] Use QDataStream for Geogrid-Viewer binary files This eliminates the need to do the manual endianess handling and converting binary data into a double. Works on SPARC64 as well (big endian). --- ggv_bin.cc | 355 ++++++++++++++++++++++++++--------------------------- 1 file changed, 174 insertions(+), 181 deletions(-) diff --git a/ggv_bin.cc b/ggv_bin.cc index 1d64f4da8..9f25f742d 100644 --- a/ggv_bin.cc +++ b/ggv_bin.cc @@ -36,36 +36,32 @@ static QString read_fname; ***************************************************************************/ static void -ggv_bin_read_bytes(QFile& file, QByteArray& buf, qint64 size, const char* descr = NULL) +ggv_bin_read_bytes(QDataStream& stream, QByteArray& buf, qint64 len, const char* descr = NULL) { - if (size > file.size()) - fatal(MYNAME ": Read size error (%s)\n", descr ? descr : ""); - buf = file.read(size); - if (buf.size() < size) + buf.resize(len); + if (stream.readRawData(buf.data(), len) != len || stream.status() != QDataStream::Ok) fatal(MYNAME ": Read error (%s)\n", descr ? descr : ""); } static quint16 -ggv_bin_read16(QFile& file, const char* descr = NULL) +ggv_bin_read16(QDataStream& stream, const char* descr = NULL) { - QByteArray buf; quint16 res; - - ggv_bin_read_bytes(file, buf, 2, descr); - res = qFromLittleEndian((const uchar*)buf.constData()); + stream >> res; + if (stream.status() != QDataStream::Ok) + fatal(MYNAME ": Read error (%s)\n", descr ? descr : ""); if (global_opts.debug_level > 1) qDebug("ovl: %-15s %5u (0x%04x)", descr, res, res); return res; } static quint32 -ggv_bin_read32(QFile& file, const char* descr = NULL) +ggv_bin_read32(QDataStream& stream, const char* descr = NULL) { - QByteArray buf; quint32 res; - - ggv_bin_read_bytes(file, buf, 4, descr); - res = qFromLittleEndian((const uchar*)buf.constData()); + stream >> res; + if (stream.status() != QDataStream::Ok) + fatal(MYNAME ": Read error (%s)\n", descr ? descr : ""); if (global_opts.debug_level > 1) { if ((res & 0xFFFF0000) == 0) qDebug("ovl: %-15s %5u (0x%08x)", descr, res, res); @@ -76,40 +72,33 @@ ggv_bin_read32(QFile& file, const char* descr = NULL) } static void -ggv_bin_read_text16(QFile& file, QByteArray& buf, const char* descr = NULL) +ggv_bin_read_text16(QDataStream& stream, QByteArray& buf, const char* descr = NULL) { - quint16 len; - - len = ggv_bin_read16(file, descr); - ggv_bin_read_bytes(file, buf, len, descr); + quint16 len = ggv_bin_read16(stream, descr); + ggv_bin_read_bytes(stream, buf, len, descr); buf[len] = 0; if (global_opts.debug_level > 1) qDebug() << "ovl: text =" << QString::fromLatin1(buf.constData()).simplified(); } static void -ggv_bin_read_text32(QFile& file, QByteArray& buf, const char* descr = NULL) +ggv_bin_read_text32(QDataStream& stream, QByteArray& buf, const char* descr = NULL) { - quint32 len; - - len = ggv_bin_read32(file, descr); - ggv_bin_read_bytes(file, buf, len, descr); + quint32 len = ggv_bin_read32(stream, descr); + ggv_bin_read_bytes(stream, buf, len, descr); buf[len] = 0; if (global_opts.debug_level > 1) qDebug() << "ovl: text =" << QString::fromLatin1(buf.constData()).simplified(); } static double -ggv_bin_read_double(QFile& file, const char* descr = NULL) +ggv_bin_read_double(QDataStream& stream, const char* descr = NULL) { - QByteArray buf; - quint64 tmp; - const double *res; - - ggv_bin_read_bytes(file, buf, sizeof(double), descr); - tmp = qFromLittleEndian((const uchar*)buf.constData()); - res = reinterpret_cast(&tmp); - return *res; + double res; + stream >> res; + if (stream.status() != QDataStream::Ok) + fatal(MYNAME ": Read error (%s)\n", descr ? descr : ""); + return res; } /*************************************************************************** @@ -117,7 +106,7 @@ ggv_bin_read_double(QFile& file, const char* descr = NULL) ***************************************************************************/ static void -ggv_bin_read_v2(QFile& file) +ggv_bin_read_v2(QDataStream& stream) { QByteArray buf; QString track_name; @@ -132,26 +121,26 @@ ggv_bin_read_v2(QFile& file) quint64 entry_pos; // header length is usually either 0x90 or 0x00 - header_len = ggv_bin_read16(file, "map name len"); + header_len = ggv_bin_read16(stream, "map name len"); if (header_len > 0) { - ggv_bin_read_bytes(file, buf, header_len, "map name"); + ggv_bin_read_bytes(stream, buf, header_len, "map name"); buf.remove(0,4); buf.append('\0'); if (global_opts.debug_level > 1) qDebug() << "ovl: name =" << buf.constData(); } - while (!file.atEnd()) { + while (!stream.atEnd()) { track_name.clear(); if (global_opts.debug_level > 1) - qDebug("------------------------------------ 0x%llx", file.pos()); + qDebug("------------------------------------ 0x%llx", stream.device()->pos()); - entry_pos = file.pos(); - entry_type = ggv_bin_read16(file, "entry type"); - ggv_bin_read16(file, "entry group"); - ggv_bin_read16(file, "entry zoom"); - entry_subtype = ggv_bin_read16(file, "entry subtype"); + entry_pos = stream.device()->pos(); + entry_type = ggv_bin_read16(stream, "entry type"); + ggv_bin_read16(stream, "entry group"); + ggv_bin_read16(stream, "entry zoom"); + entry_subtype = ggv_bin_read16(stream, "entry subtype"); switch (entry_subtype) { case 0x01: @@ -159,7 +148,7 @@ ggv_bin_read_v2(QFile& file) break; case 0x10: // text with 32 bit length field follows - ggv_bin_read_text32(file, buf, "text len"); + ggv_bin_read_text32(stream, buf, "text len"); track_name = QString::fromLatin1(buf.constData()).simplified(); break; default: @@ -169,14 +158,14 @@ ggv_bin_read_v2(QFile& file) switch (entry_type) { case 0x02: // text - ggv_bin_read16(file, "text color"); - ggv_bin_read16(file, "text size"); - ggv_bin_read16(file, "text trans"); - ggv_bin_read16(file, "text font"); - ggv_bin_read16(file, "text angle"); - lon = ggv_bin_read_double(file, "text lon"); - lat = ggv_bin_read_double(file, "text lat"); - ggv_bin_read_text16(file, buf, "text label"); + ggv_bin_read16(stream, "text color"); + ggv_bin_read16(stream, "text size"); + ggv_bin_read16(stream, "text trans"); + ggv_bin_read16(stream, "text font"); + ggv_bin_read16(stream, "text angle"); + lon = ggv_bin_read_double(stream, "text lon"); + lat = ggv_bin_read_double(stream, "text lat"); + ggv_bin_read_text16(stream, buf, "text label"); waypt_name = QString::fromLatin1(buf.constData()).simplified(); wpt = new Waypoint; wpt->longitude = lon; @@ -188,18 +177,18 @@ ggv_bin_read_v2(QFile& file) // line case 0x04: // area - ggv_bin_read16(file, "line color"); - ggv_bin_read16(file, "line width"); - ggv_bin_read16(file, "line type"); - line_points = ggv_bin_read16(file, "line points"); + ggv_bin_read16(stream, "line color"); + ggv_bin_read16(stream, "line width"); + ggv_bin_read16(stream, "line type"); + line_points = ggv_bin_read16(stream, "line points"); ggv_bin_track = route_head_alloc(); track_add_head(ggv_bin_track); if (! track_name.isEmpty()) ggv_bin_track->rte_name = track_name; for (int i = 1; i <= line_points; i++) { - lon = ggv_bin_read_double(file, "line lon"); - lat = ggv_bin_read_double(file, "line lat"); + lon = ggv_bin_read_double(stream, "line lon"); + lat = ggv_bin_read_double(stream, "line lat"); wpt = new Waypoint; wpt->longitude = lon; wpt->latitude = lat; @@ -212,23 +201,23 @@ ggv_bin_read_v2(QFile& file) // circle case 0x07: // triangle - ggv_bin_read16(file, "geom color"); - ggv_bin_read16(file, "geom prop1"); - ggv_bin_read16(file, "geom prop2"); - ggv_bin_read16(file, "geom angle"); - ggv_bin_read16(file, "geom stroke"); - ggv_bin_read16(file, "geom area"); - ggv_bin_read_double(file, "geom lon"); - ggv_bin_read_double(file, "geom lat"); + ggv_bin_read16(stream, "geom color"); + ggv_bin_read16(stream, "geom prop1"); + ggv_bin_read16(stream, "geom prop2"); + ggv_bin_read16(stream, "geom angle"); + ggv_bin_read16(stream, "geom stroke"); + ggv_bin_read16(stream, "geom area"); + ggv_bin_read_double(stream, "geom lon"); + ggv_bin_read_double(stream, "geom lat"); break; case 0x09: - ggv_bin_read16(file, "bmp color"); - ggv_bin_read16(file, "bmp prop1"); - ggv_bin_read16(file, "bmp prop2"); - ggv_bin_read16(file, "bmp prop3"); - ggv_bin_read_double(file, "bmp lon"); - ggv_bin_read_double(file, "bmp lat"); - ggv_bin_read_text32(file, buf, "bmp data"); + ggv_bin_read16(stream, "bmp color"); + ggv_bin_read16(stream, "bmp prop1"); + ggv_bin_read16(stream, "bmp prop2"); + ggv_bin_read16(stream, "bmp prop3"); + ggv_bin_read_double(stream, "bmp lon"); + ggv_bin_read_double(stream, "bmp lat"); + ggv_bin_read_text32(stream, buf, "bmp data"); break; default: fatal(MYNAME ": Unknown entry type (0x%hx, pos=0x%llx) \n", entry_type, entry_pos); @@ -241,24 +230,24 @@ ggv_bin_read_v2(QFile& file) ***************************************************************************/ static void -ggv_bin_read_v34_header(QFile& file, quint32& number_labels, quint32 &number_records) +ggv_bin_read_v34_header(QDataStream& stream, quint32& number_labels, quint32 &number_records) { QByteArray buf; quint16 header_len; - ggv_bin_read_bytes(file, buf, 8, "unknown"); - number_labels = ggv_bin_read32(file, "num labels"); - number_records = ggv_bin_read32(file, "num records"); - ggv_bin_read_text16(file, buf, "text label"); - ggv_bin_read16(file, "unknown"); - ggv_bin_read16(file, "unknown"); + ggv_bin_read_bytes(stream, buf, 8, "unknown"); + number_labels = ggv_bin_read32(stream, "num labels"); + number_records = ggv_bin_read32(stream, "num records"); + ggv_bin_read_text16(stream, buf, "text label"); + ggv_bin_read16(stream, "unknown"); + ggv_bin_read16(stream, "unknown"); // 8 bytes ending with 1E 00, contains len of header block - ggv_bin_read16(file, "unknown"); - header_len = ggv_bin_read16(file, "header len"); - ggv_bin_read16(file, "unknown"); - ggv_bin_read16(file, "unknown"); + ggv_bin_read16(stream, "unknown"); + header_len = ggv_bin_read16(stream, "header len"); + ggv_bin_read16(stream, "unknown"); + ggv_bin_read16(stream, "unknown"); if (header_len > 0) { - ggv_bin_read_bytes(file, buf, header_len, "map name"); + ggv_bin_read_bytes(stream, buf, header_len, "map name"); buf.remove(0,4); buf.append('\0'); if (global_opts.debug_level > 1) @@ -267,52 +256,52 @@ ggv_bin_read_v34_header(QFile& file, quint32& number_labels, quint32 &number_rec } static void -ggv_bin_read_v34_label(QFile& file) +ggv_bin_read_v34_label(QDataStream& stream) { QByteArray buf; if (global_opts.debug_level > 1) - qDebug("------------------------------------ 0x%llx", file.pos()); - ggv_bin_read_bytes(file, buf, 0x08, "label header"); - ggv_bin_read_bytes(file, buf, 0x14, "label number"); - ggv_bin_read_text16(file, buf, "label text"); - ggv_bin_read16(file, "label flag1"); - ggv_bin_read16(file, "label flag2"); + qDebug("------------------------------------ 0x%llx", stream.device()->pos()); + ggv_bin_read_bytes(stream, buf, 0x08, "label header"); + ggv_bin_read_bytes(stream, buf, 0x14, "label number"); + ggv_bin_read_text16(stream, buf, "label text"); + ggv_bin_read16(stream, "label flag1"); + ggv_bin_read16(stream, "label flag2"); } static QString -ggv_bin_read_v34_common(QFile& file) +ggv_bin_read_v34_common(QDataStream& stream) { QByteArray buf; QString res; quint16 type1; quint16 type2; - ggv_bin_read16(file, "entry group"); - ggv_bin_read16(file, "entry prop2"); - ggv_bin_read16(file, "entry prop3"); - ggv_bin_read16(file, "entry prop4"); - ggv_bin_read16(file, "entry prop5"); - ggv_bin_read16(file, "entry prop6"); - ggv_bin_read16(file, "entry prop7"); - ggv_bin_read16(file, "entry prop8"); - ggv_bin_read16(file, "entry zoom"); - ggv_bin_read16(file, "entry prop10"); - ggv_bin_read_text16(file, buf, "entry txt"); + ggv_bin_read16(stream, "entry group"); + ggv_bin_read16(stream, "entry prop2"); + ggv_bin_read16(stream, "entry prop3"); + ggv_bin_read16(stream, "entry prop4"); + ggv_bin_read16(stream, "entry prop5"); + ggv_bin_read16(stream, "entry prop6"); + ggv_bin_read16(stream, "entry prop7"); + ggv_bin_read16(stream, "entry prop8"); + ggv_bin_read16(stream, "entry zoom"); + ggv_bin_read16(stream, "entry prop10"); + ggv_bin_read_text16(stream, buf, "entry txt"); res = QString::fromLatin1(buf.constData()).simplified(); - type1 = ggv_bin_read16(file, "entry type1"); + type1 = ggv_bin_read16(stream, "entry type1"); if (type1 != 1) { - ggv_bin_read_text32(file, buf, "entry object"); + ggv_bin_read_text32(stream, buf, "entry object"); } - type2 = ggv_bin_read16(file, "entry type2"); + type2 = ggv_bin_read16(stream, "entry type2"); if (type2 != 1) { - ggv_bin_read_text32(file, buf, "entry object"); + ggv_bin_read_text32(stream, buf, "entry object"); } return res; } static void -ggv_bin_read_v34_record(QFile& file) +ggv_bin_read_v34_record(QDataStream& stream) { QByteArray buf; QString label; @@ -324,26 +313,26 @@ ggv_bin_read_v34_record(QFile& file) double lon, lat; if (global_opts.debug_level > 1) - qDebug("------------------------------------ 0x%llx", file.pos()); + qDebug("------------------------------------ 0x%llx", stream.device()->pos()); - entry_type = ggv_bin_read16(file, "entry type"); - label = ggv_bin_read_v34_common(file); + entry_type = ggv_bin_read16(stream, "entry type"); + label = ggv_bin_read_v34_common(stream); switch (entry_type) { case 0x02: // text - ggv_bin_read16(file, "text prop1"); - ggv_bin_read32(file, "text prop2"); - ggv_bin_read16(file, "text prop3"); - ggv_bin_read32(file, "text prop4"); - ggv_bin_read16(file, "text ltype"); - ggv_bin_read16(file, "text angle"); - ggv_bin_read16(file, "text size"); - ggv_bin_read16(file, "text area"); - lon = ggv_bin_read_double(file, "text lon"); - lat = ggv_bin_read_double(file, "text lat"); - ggv_bin_read_double(file, "text unk"); - ggv_bin_read_text16(file, buf, "text label"); + ggv_bin_read16(stream, "text prop1"); + ggv_bin_read32(stream, "text prop2"); + ggv_bin_read16(stream, "text prop3"); + ggv_bin_read32(stream, "text prop4"); + ggv_bin_read16(stream, "text ltype"); + ggv_bin_read16(stream, "text angle"); + ggv_bin_read16(stream, "text size"); + ggv_bin_read16(stream, "text area"); + lon = ggv_bin_read_double(stream, "text lon"); + lat = ggv_bin_read_double(stream, "text lat"); + ggv_bin_read_double(stream, "text unk"); + ggv_bin_read_text16(stream, buf, "text label"); wpt = new Waypoint; wpt->longitude = lon; wpt->latitude = lat; @@ -361,22 +350,22 @@ ggv_bin_read_v34_record(QFile& file) if (! label.isEmpty()) ggv_bin_track->rte_name = label; - ggv_bin_read16(file, "line prop1"); - ggv_bin_read32(file, "line prop2"); - ggv_bin_read16(file, "line prop3"); - ggv_bin_read32(file, "line color"); - ggv_bin_read16(file, "line size"); - ggv_bin_read16(file, "line stroke"); - line_points = ggv_bin_read16(file, "line points"); + ggv_bin_read16(stream, "line prop1"); + ggv_bin_read32(stream, "line prop2"); + ggv_bin_read16(stream, "line prop3"); + ggv_bin_read32(stream, "line color"); + ggv_bin_read16(stream, "line size"); + ggv_bin_read16(stream, "line stroke"); + line_points = ggv_bin_read16(stream, "line points"); if (entry_type == 0x04) { // found in example.ovl generated by Geogrid-Viewer 1.0 - ggv_bin_read16(file, "line pad"); + ggv_bin_read16(stream, "line pad"); } for (int i=1; i <= line_points; i++) { - lon = ggv_bin_read_double(file, "line lon"); - lat = ggv_bin_read_double(file, "line lat"); - ggv_bin_read_double(file, "line unk"); + lon = ggv_bin_read_double(stream, "line lon"); + lat = ggv_bin_read_double(stream, "line lat"); + ggv_bin_read_double(stream, "line unk"); wpt = new Waypoint; wpt->longitude = lon; wpt->latitude = lat; @@ -387,34 +376,34 @@ ggv_bin_read_v34_record(QFile& file) case 0x06: case 0x07: // circle - ggv_bin_read16(file, "circle prop1"); - ggv_bin_read32(file, "circle prop2"); - ggv_bin_read16(file, "circle prop3"); - ggv_bin_read32(file, "circle color"); - ggv_bin_read32(file, "circle prop5"); - ggv_bin_read32(file, "circle prop6"); - ggv_bin_read16(file, "circle ltype"); - ggv_bin_read16(file, "circle angle"); - ggv_bin_read16(file, "circle size"); - ggv_bin_read16(file, "circle area"); - ggv_bin_read_double(file, "circle lon"); - ggv_bin_read_double(file, "circle lat"); - ggv_bin_read_double(file, "circle unk"); + ggv_bin_read16(stream, "circle prop1"); + ggv_bin_read32(stream, "circle prop2"); + ggv_bin_read16(stream, "circle prop3"); + ggv_bin_read32(stream, "circle color"); + ggv_bin_read32(stream, "circle prop5"); + ggv_bin_read32(stream, "circle prop6"); + ggv_bin_read16(stream, "circle ltype"); + ggv_bin_read16(stream, "circle angle"); + ggv_bin_read16(stream, "circle size"); + ggv_bin_read16(stream, "circle area"); + ggv_bin_read_double(stream, "circle lon"); + ggv_bin_read_double(stream, "circle lat"); + ggv_bin_read_double(stream, "circle unk"); break; case 0x09: // bmp - ggv_bin_read16(file, "bmp prop1"); - ggv_bin_read32(file, "bmp prop2"); - ggv_bin_read16(file, "bmp prop3"); - ggv_bin_read32(file, "bmp prop4"); - ggv_bin_read32(file, "bmp prop5"); - ggv_bin_read32(file, "bmp prop6"); - ggv_bin_read_double(file, "bmp lon"); - ggv_bin_read_double(file, "bmp lat"); - ggv_bin_read_double(file, "bmp unk"); - bmp_len = ggv_bin_read32(file, "bmp len"); - ggv_bin_read16(file, "bmp prop"); - ggv_bin_read_bytes(file, buf, bmp_len, "bmp data"); + ggv_bin_read16(stream, "bmp prop1"); + ggv_bin_read32(stream, "bmp prop2"); + ggv_bin_read16(stream, "bmp prop3"); + ggv_bin_read32(stream, "bmp prop4"); + ggv_bin_read32(stream, "bmp prop5"); + ggv_bin_read32(stream, "bmp prop6"); + ggv_bin_read_double(stream, "bmp lon"); + ggv_bin_read_double(stream, "bmp lat"); + ggv_bin_read_double(stream, "bmp unk"); + bmp_len = ggv_bin_read32(stream, "bmp len"); + ggv_bin_read16(stream, "bmp prop"); + ggv_bin_read_bytes(stream, buf, bmp_len, "bmp data"); break; default: fatal(MYNAME ": Unsupported type: %x\n", entry_type); @@ -422,45 +411,45 @@ ggv_bin_read_v34_record(QFile& file) } static void -ggv_bin_read_v34(QFile& file) +ggv_bin_read_v34(QDataStream& stream) { QByteArray buf; QString track_name; quint32 label_count; quint32 record_count; - while (!file.atEnd()) { - ggv_bin_read_v34_header(file, label_count, record_count); + while (!stream.atEnd()) { + ggv_bin_read_v34_header(stream, label_count, record_count); - if (label_count && !file.atEnd()) { + if (label_count && !stream.atEnd()) { if (global_opts.debug_level > 1) - qDebug("-----labels------------------------- 0x%llx", file.pos()); + qDebug("-----labels------------------------- 0x%llx", stream.device()->pos()); for (unsigned int i = 0; i < label_count; i++) - ggv_bin_read_v34_label(file); + ggv_bin_read_v34_label(stream); } - if (record_count && !file.atEnd()) { + if (record_count && !stream.atEnd()) { if (global_opts.debug_level > 1) - qDebug("-----records------------------------ 0x%llx", file.pos()); + qDebug("-----records------------------------ 0x%llx", stream.device()->pos()); for (unsigned int i = 0; i < record_count; i++) - ggv_bin_read_v34_record(file); + ggv_bin_read_v34_record(stream); } - if (!file.atEnd()) { + if (!stream.atEnd()) { if (global_opts.debug_level > 1) - qDebug("------------------------------------ 0x%llx", file.pos()); + qDebug("------------------------------------ 0x%llx", stream.device()->pos()); // we just skip over the next magic bytes without checking they // contain the correct string. This is consistent with what I // believe GGV does - ggv_bin_read_bytes(file, buf, 23, "magicbytes"); + ggv_bin_read_bytes(stream, buf, 23, "magicbytes"); if (global_opts.debug_level > 1) qDebug() << "ovl: header = " << buf.constData(); } } if (global_opts.debug_level > 1) { - qDebug("fpos: 0x%llx", file.pos()); - qDebug("size: 0x%llx", file.size()); + qDebug("fpos: 0x%llx", stream.device()->pos()); + qDebug("size: 0x%llx", stream.device()->size()); } } @@ -469,22 +458,22 @@ ggv_bin_read_v34(QFile& file) ***************************************************************************/ static void -ggv_bin_read_file(QFile& file) +ggv_bin_read_file(QDataStream& stream) { QByteArray buf; - ggv_bin_read_bytes(file, buf, 0x17, "magic"); + ggv_bin_read_bytes(stream, buf, 0x17, "magic"); buf[23] = 0; if (global_opts.debug_level > 1) { qDebug() << "ovl: header =" << buf.constData(); } if (buf.startsWith("DOMGVCRD Ovlfile V2.0")) { - ggv_bin_read_v2(file); + ggv_bin_read_v2(stream); } else if (buf.startsWith("DOMGVCRD Ovlfile V3.0")) { - ggv_bin_read_v34(file); + ggv_bin_read_v34(stream); } else if (buf.startsWith("DOMGVCRD Ovlfile V4.0")) { - ggv_bin_read_v34(file); + ggv_bin_read_v34(stream); } else { fatal(MYNAME ": Unsupported file format\n"); } @@ -510,7 +499,11 @@ ggv_bin_read(void) fatal(MYNAME ": Error opening file %s\n", read_fname.toStdString().c_str()); } - ggv_bin_read_file(file); + QDataStream stream(&file); + stream.setFloatingPointPrecision(QDataStream::DoublePrecision); + stream.setByteOrder(QDataStream::LittleEndian); + + ggv_bin_read_file(stream); file.close(); } -- 2.30.2